﻿
#region 文件信息
/*----------------------------------------------------------------
// 
// 文件名称：	
// 文件功能描述：	
// 设计要求：	
//
// 文 件 名：    DTOGenerator
// 创建者：      杨程
// 创建日期：	    2023/2/6 15:31:48

//----------------------------------------------------------------*/
#endregion

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace Vampirewal.Core.SourceGeneratorMvvm.Generators;

public class DtoSyntaxReceiver : ISyntaxReceiver
{
    public List<AttributeSyntax> CandidateClasses { get; }=new List<AttributeSyntax>();

    public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
    {
        //if ((syntaxNode is ClassDeclarationSyntax cds)&&cds.AttributeLists.Count>0&& cds.Identifier.Value is IdentifierNameSyntax identifierName)
        //{

        //    CandidateClasses.Add(cds);
        //}

        if (syntaxNode is AttributeSyntax cds && cds.Name is IdentifierNameSyntax identifierName && identifierName.Identifier.ValueText == "GeneratorDTO")
        {
            CandidateClasses.Add(cds);
        }
    }
}

/// <summary>
/// 生成DTO文件
/// </summary>
[Generator]
public partial class DTOGenerator : ISourceGenerator
{
    public void Execute(GeneratorExecutionContext context)
    {
        var syntaxReceiver = (DtoSyntaxReceiver)context.SyntaxReceiver;
        var attributeSyntaxList = syntaxReceiver.CandidateClasses;

        if (attributeSyntaxList.Count == 0)
        {
            return;
        }

        List<string> ClassName = new List<string>();

        foreach (AttributeSyntax attributeSyntax in attributeSyntaxList)
        {
            // 找到class，并且判断一下是否有parital字段
            var classDeclarationSyntax = attributeSyntax.FirstAncestorOrSelf<ClassDeclarationSyntax>();
            if (classDeclarationSyntax == null ||!classDeclarationSyntax.Modifiers.Any(m => m.IsKind(SyntaxKind.PartialKeyword)))
            {
                throw new Exception("该类不是Partial");
                //continue;
            }

            // 找到namespace
            var namespaceDeclarationSyntax = classDeclarationSyntax.FirstAncestorOrSelf<BaseNamespaceDeclarationSyntax>();  
            if (ClassName.Contains(classDeclarationSyntax.Identifier.ValueText))
            {
                continue;
            }

            // 找到property
            var propertyDeclarationList = classDeclarationSyntax.Members.OfType<PropertyDeclarationSyntax>().ToList();
            if (propertyDeclarationList.Count == 0)
            {
                continue;
            }


            StringBuilder sb = new StringBuilder();

            sb.AppendLine("// <auto-generated/>");
            sb.AppendLine("#pragma warning disable");
            sb.AppendLine("#nullable enable");
            sb.AppendLine();
            sb.AppendLine("using System;");
            //sb.AppendLine("using Newtonsoft.Json;");
            sb.AppendLine();
            sb.AppendLine($"namespace {namespaceDeclarationSyntax.Name.ToString()}");
            sb.AppendLine("{");
            sb.AppendLine($"    /// <summary>");
            sb.AppendLine($"    /// {classDeclarationSyntax.Identifier.Text}的DTO类");
            sb.AppendLine($"    /// </summary>");
            sb.AppendLine($"    public partial class {classDeclarationSyntax.Identifier.Text}DTO");
            sb.AppendLine("    {");

            #region 生成DTO属性
            foreach (PropertyDeclarationSyntax prop in propertyDeclarationList)
            {
                //再判断一下属性上是否标记了DtoIgnore特性,没有的话继续，有的话，就不继续了
                if (SyntaxUtils.HasAttribute(prop, "DtoIgnore"))
                {
                    continue;
                }

                var type = prop.Type.ToString();

                var name = prop.Identifier.Text;

                sb.AppendLine();
                sb.AppendLine($"        /// <summary>");
                sb.AppendLine($"        /// <see cref=\"{name}\"/>");
                sb.AppendLine($"        /// </summary>");
                sb.AppendLine("        [global::Newtonsoft.Json.JsonProperty(\"" + Utils.ConvertToCamel(name, "_") + "\")]");
                sb.AppendLine($"        public {type} {name} " + "{get; set;}");
                sb.AppendLine();
            }
            #endregion

            #region 生成转换方法
            sb.AppendLine($"        /// <summary>");
            sb.AppendLine($"        /// 将{classDeclarationSyntax.Identifier.Text}DTO转成{classDeclarationSyntax.Identifier.Text}类");
            sb.AppendLine($"        /// </summary>");
            sb.AppendLine($"        /// <returns>{classDeclarationSyntax.Identifier.Text}</returns>");
            sb.AppendLine($"        public {classDeclarationSyntax.Identifier.Text} FromDTO()");
            sb.AppendLine("        {");
            sb.AppendLine($"            {classDeclarationSyntax.Identifier.Text} vo=new {classDeclarationSyntax.Identifier.Text}(); ");

            foreach (PropertyDeclarationSyntax prop in propertyDeclarationList)
            {
                //再判断一下属性上是否标记了DtoIgnore特性,没有的话继续，有的话，就不继续了
                if (SyntaxUtils.HasAttribute(prop, "DtoIgnore"))
                {
                    continue;
                }

                sb.AppendLine($"            vo.{prop.Identifier.Text}=this.{prop.Identifier.Text};");
            }
            sb.AppendLine("            return vo;");

            sb.AppendLine("        }");
            #endregion


            sb.AppendLine("    }");

            sb.AppendLine("}");

            context.AddSource($"{classDeclarationSyntax.Identifier.Text}DTO.cs", SourceText.From(sb.ToString(), Encoding.UTF8));
        }


        //var options = (context.Compilation as CSharpCompilation).SyntaxTrees[0].Options as CSharpParseOptions;
        //var compilation = context.Compilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(Utils.GetTemplateByFileName("AttributeTemplate.GeneratorDTOStr.txt"), options));

        //var allNodes = compilation.SyntaxTrees.SelectMany(s => s.GetRoot().DescendantNodes());
        //var allAttributes = allNodes.Where((d) => d.IsKind(SyntaxKind.Attribute)).OfType<AttributeSyntax>();
        //var attributes = allAttributes.Where(d => d.Name.ToString() == "GeneratorDTO").ToList();

        //var allClasses = compilation.SyntaxTrees.SelectMany(x => x.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>());

        //List<string> ClassName = new List<string>();
        //foreach (AttributeSyntax attr in attributes)
        //{
        //    var TypeArgSyntax = attr.ArgumentList.Arguments.First();
        //    var TypeArgSyntaxExpr = TypeArgSyntax.Expression.NormalizeWhitespace().ToFullString();

        //    //找到CLASS
        //    var toClassName = Utils.GetContentInParentheses(TypeArgSyntaxExpr);
        //    if (ClassName.Any(a => a.Equals(toClassName)))
        //    {
        //        continue;
        //    }
        //    ClassName.Add(toClassName);

        //    var toClassSyntax = allClasses.First(x => x.Identifier.ToString() == toClassName);

        //    // 找到namespace
        //    var namespaceDeclarationSyntax = toClassSyntax.FirstAncestorOrSelf<BaseNamespaceDeclarationSyntax>();



        //    var toClassModel = compilation.GetSemanticModel(toClassSyntax.SyntaxTree);
        //    var toClassNamedTypeSymbol = ModelExtensions.GetDeclaredSymbol(toClassModel, toClassSyntax);
        //    var toClassFullName = toClassNamedTypeSymbol.OriginalDefinition.ToString();

        //    // 找到field
        //    var propertyDeclarationList = toClassSyntax.Members.OfType<PropertyDeclarationSyntax>().ToList();

        //    StringBuilder sb = new StringBuilder();

        //    sb.AppendLine("using System;");
        //    //sb.AppendLine("using Newtonsoft.Json;");
        //    sb.AppendLine();
        //    sb.AppendLine($"namespace {namespaceDeclarationSyntax.Name.ToString()}");
        //    sb.AppendLine("{");
        //    sb.AppendLine($"    /// <summary>");
        //    sb.AppendLine($"    /// {toClassSyntax.Identifier.Text}的DTO类");
        //    sb.AppendLine($"    /// </summary>");
        //    sb.AppendLine($"    public partial class {toClassSyntax.Identifier.Text}DTO");
        //    sb.AppendLine("    {");



        //    if(propertyDeclarationList.Count == 0)
        //    {
        //        sb.AppendLine($"    // 原始类中不包含属性！");
        //    }

        //    //[JsonProperty("")]
        //    foreach (PropertyDeclarationSyntax prop in propertyDeclarationList)
        //    {
        //        var type = prop.Type.ToString();

        //        var name = prop.Identifier.Text;


        //        sb.AppendLine();
        //        sb.AppendLine("        [global::Newtonsoft.Json.JsonProperty(\"" + Utils.ConvertToCamel(name, "_") + "\")]");
        //        sb.AppendLine($"        public {type} {name} " + "{get; set;}");
        //        sb.AppendLine();

        //    }
        //    sb.AppendLine("    }");



        //    sb.AppendLine("}");

        //    context.AddSource($"{toClassSyntax.Identifier.Text}.g.cs", SourceText.From(sb.ToString(), Encoding.UTF8));
        //}
    }

    public void Initialize(GeneratorInitializationContext context)
    {
#if DEBUG
        //Debugger.Launch();
#endif

        context.RegisterForSyntaxNotifications(() => new DtoSyntaxReceiver());
    }
}

internal class ClassModel
{
    public string Namespace { get; set; }

    public string Class { get; set; }

    public List<Field> Fields { get; set; }
    public List<string> Usings { get; set; }
}

internal class Field
{
    public string Type { get; set; }

    public string Name { get; set; }
    public bool IsOptions { get; set; }
}
